package main

import (
	"fmt"
	"time"
)

func say(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(10 * time.Millisecond)
		fmt.Printf(s)
	}
}

func sum(a []int, c chan int) {
	sum := 0
	for _, v := range a {
		sum += v
	}
	c <- sum // 将和送入 c
}

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)
}

func fibonacci2(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

func Run6() {
	fmt.Println("Run6 --------------------------------")

	// goroutine 运行时环境管理的轻量级线程
	go say("+")
	say(".")
	time.Sleep(100 * time.Millisecond)
	fmt.Printf("\n----------\n")

	// channel 管道
	// 默认无缓存，读写阻塞，可以不用锁
	a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	c := make(chan int)
	go sum(a[len(a)/2:], c) // 1~5
	go sum(a[:len(a)/2], c) // 6~10
	x, y := <-c, <-c // 阻塞直到数据写入2次
	fmt.Println(x, y, x+y)
	fmt.Printf("\n----------\n")

	// 缓冲 channel 缓冲区满的时候会阻塞
	c2 := make(chan int, 2)
	c2 <- 111
	c2 <- 222
	fmt.Println(<-c2)
	fmt.Println(<-c2)
	fmt.Printf("\n----------\n")

	// range 和 close
	//注意： 只有发送者才能关闭 channel，而不是接收者
	//通常情况下无需关闭它们
	c3 := make(chan int, 10)
	go fibonacci(cap(c3), c3)
	for i := range c3 { //不断从 channel 接收值，直到close
		fmt.Println(i)
	}
	fmt.Printf("\n----------\n")

	// select 在多个channel中阻塞接收，类似switch
	// select如果有default分支，则实现了不阻塞
	c4 := make(chan int)
	quit := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c4)
		}
		quit <- 0
	}()
	fibonacci2(c4, quit)

}


